# -*- coding: utf-8 -*-

# -------------------------------
# Author    : linlingwei
# Email     : 951035650@qq.com
# File Name : correctShape.py
# -------------------------------

__author__ = "linlingwei"

import os,time
import maya.cmds as mc
import maya.mel as mel

def checkPlugin():
    srcPath = os.path.join(os.path.dirname(__file__).rsplit("\\",1)[0])
    srcPath = os.path.normpath(srcPath)
    maya_version = mc.about(v=True)
    plugin_list = mc.pluginInfo(q=True,listPlugins=True)
    if "correctShape" not in plugin_list:
        plugin_path = os.path.join(srcPath,"plug-ins",maya_version)
        if plugin_path not in os.environ["MAYA_PLUG_IN_PATH"]:
            os.environ["MAYA_PLUG_IN_PATH"] += ";"+plugin_path
        mc.loadPlugin("correctShape.mll")
    return


def findRelateOrigShape(inobj):
    allList = mc.ls(mc.listRelatives(inobj, shapes=True, c=True), type="mesh")
    itsShapes = mc.listRelatives(inobj, shapes=1, pa=1)
    for sp in itsShapes:
        if sp not in allList:
            allList.append(sp)
    for obj in allList:
        value = mc.getAttr('%s.intermediateObject' % obj)
        upTrans = mc.listRelatives(obj, parent=True, pa=True)[0]

        sel_typ = mc.nodeType(obj)
        if sel_typ == "mesh":
            hasOutPut = mc.listConnections("%s.worldMesh" % obj, d=1)
            hasInPut = mc.listConnections("%s.inMesh" % obj, s=1, d=0)
        elif sel_typ == "nurbsCurve":
            hasOutPut = mc.listConnections("%s.worldSpace" % obj, d=1)
            hasInPut = mc.listConnections("%s.create" % obj, s=1, d=0)
        else:
            return
        if value \
                and upTrans == inobj \
                and hasOutPut is not None \
                and hasInPut is None:
            return obj


def findRelatedShape(inobj):
    controlShape, controlShapeWithPath, hiddenShape, hiddenShapeWithPath = "", "", "", ""
    cpTest = mc.ls(inobj, type="shape")
    if len(cpTest):
        return inobj
    else:
        rels = mc.listRelatives(inobj)
        
        if rels is None:
            return
        for r in rels:
            cpTest = mc.ls(inobj + "|" + r, type="shape")
            if 0 == len(cpTest):
                continue
            io = mc.getAttr(inobj + "|" + r + ".io")
            if io:
                continue
            visible = mc.getAttr(inobj + "|" + r + ".v")
            if 0 == visible:
                hiddenShape = r
                hiddenShapeWithPath = (inobj + "|" + r)
                continue
            controlShape = r
            controlShapeWithPath = (inobj + "|" + r)
            break
    for shape in [controlShape, controlShapeWithPath, hiddenShape, hiddenShapeWithPath]:
        if 0 != len(shape) and len(mc.ls(shape)) == 1:
            return shape
    return

def findRelatedBlendShape(inobj):
    deform = mel.eval('findRelatedDeformer %s'%inobj)
    if not deform:
        return
    for d in deform:
        if mc.nodeType(d) == "blendShape":
            return d


def duplicate_mesh(origMesh,name):

    origMeshShape = findRelatedShape(origMesh)
    sel_typ = mc.nodeType(origMeshShape)
    if sel_typ == "mesh":
        dmesh = mc.rename(mc.polyCube(ch=False)[0], name)
        dmeshShape = findRelatedShape(dmesh)
        mc.connectAttr(origMeshShape+".outMesh",dmeshShape+".inMesh",f=1)
    elif sel_typ == "nurbsCurve":
        dmesh = mc.rename(mc.curve(d=1,p=[0,0,0]), name)
        dmeshShape = findRelatedShape(dmesh)
        mc.connectAttr(origMeshShape+".worldSpace",dmeshShape+".create",f=1)
    else:
        return
    imo = mc.getAttr(origMeshShape+".intermediateObject")
    mc.setAttr(origMeshShape+".intermediateObject",0)
    mc.delete(dmesh,ch=True)
    if imo:
        mc.setAttr(origMeshShape+".intermediateObject",imo)

    return dmesh

def create():
    
    # outputGeometry
    star = time.clock()
    checkPlugin()
    sel = mc.ls(sl=True)
    if not sel:
        mc.warning("No Select geometry.")
        return
    sel = sel[0]
    skinClusterNode = mel.eval('findRelatedSkinCluster %s'%sel)
    if not skinClusterNode:
        mc.warning("No skinCluster Node.")
        return
    
    origShape = findRelateOrigShape(sel)
    scuplt = duplicate_mesh(sel,sel+"_scuplt")
    scupltShape = findRelatedShape(scuplt)
    output = duplicate_mesh(origShape,sel+"_tgt")
    sel_typ = mc.nodeType(origShape)
    # support mesh and nurbsCurve
    if sel_typ == "mesh":
        correctShapeNode =mc.deformer(output,typ="correctMesh",name=sel+"_correctMesh")[0]
        out_attr = "outMesh"
    elif sel_typ == "nurbsCurve":
        correctShapeNode = mc.deformer(output,typ="correctCurve", name=sel + "_correctCurve")[0]
        out_attr = "worldSpace"
    else:
        return
    # inheritance blendshape pose
    bls = findRelatedBlendShape(sel)
    if bls:
        # print (bls)
        mc.connectAttr(bls+".outputGeometry[0]",correctShapeNode+".pose")
        mc.dgdirty(correctShapeNode+".pose")
        mc.disconnectAttr(bls + ".outputGeometry[0]", correctShapeNode+".pose")
    else:
        # print (origShape)
        mc.connectAttr(origShape+"."+out_attr,correctShapeNode+".pose")
        mc.dgdirty(correctShapeNode+".pose")
        mc.disconnectAttr(origShape+"."+out_attr, correctShapeNode+".pose")
    
    #     sculpt
    mc.connectAttr(scupltShape+"."+out_attr,correctShapeNode+".sculpt")
    #     sculpt_orig
    mc.connectAttr(scupltShape + "." + out_attr, correctShapeNode + ".sculpt_orig")
    mc.dgdirty(correctShapeNode + ".sculpt_orig")
    mc.disconnectAttr(scupltShape + "." + out_attr, correctShapeNode + ".sculpt_orig")
    
    # offset world position
    bound_box = mc.polyEvaluate(sel,b=True)[0]
    max_width = 1.5*abs(bound_box[0]-bound_box[1])
    mc.setAttr(scuplt+".tx",max_width)
    mc.setAttr(output + ".tx", 2*max_width)
    # refresh correctShape node
    reset(correctShapeNode,sel)

    print(time.clock()-star,2)
    return


def reset(csNode,skinObj):
    if not mc.objExists(csNode):
        return
    mel.eval('createCorrectShape -c %s -s %s'%(csNode,skinObj))
    
    return


if __name__ == '__main__':
    pass